package c2.group.business.teampvp.sub;

import c2.group.business.base.GroupSubModule;
import c2.group.business.teampvp.TeamPvpModule;
import c2.group.business.teampvp.TeamPvpPlayer;
import c2.group.business.teampvp.TeamPvpTeam;
import cate.game.pvp.teampvp.dto.*;
import cate.common.util.GameResult;
import cate.game.pvp.teampvp.TeamPvpMsg;
import cate.game.rank.po.Rank;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static cate.game.pvp.teampvp.TeamPvpReqParams.*;


public class TeamPvpRecvModule extends GroupSubModule<TeamPvpModule> {
    @Override
    public void initDependent() {
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.INVITE_LIST, TeamPvpInviteListReq.class,
                (h, req) -> this.getInviteList(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.INVITE_APPLY, TeamPvpInviteApplyReq.class,
                (h, req) -> this.handleInviteApply(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.INVITE_ANSWER, TeamPvpInviteAnswerReq.class,
                (h, req) -> this.handleInviteAnswer(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.INVITE_APPLY_LIST, String.class,
                (h, req) -> this.getInviteApplyList(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.SEARCH_NAME, String.class,
                (h, req) -> this.searchPlayer(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.SYNC_TEAM_DATA, SyncTeamDataReq.class,
                (h, req) -> this.syncTeamData(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.CHANGE_LEADER, ChangeLeaderReq.class,
                (h, req) -> this.changeLeader(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.EXIT_TEAM, ExitTeamReq.class,
                (h, req) -> this.exitTeam(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.BEGIN_TO_MATCH, String.class,
                (h, req) -> this.beginToMatch(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.MATCH_REFRESH, String.class,
                (h, req) -> this.matchRefresh(req));
        useRpcRecv().onFireAndForgetTemplate(TeamPvpMsg.BEGIN_TO_CHALLENGE, String.class,
                (h, req) -> this.beginToChallenge(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.AHEAD_TO_POSITION, String.class,
                (h, req) -> this.aheadToPosition(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.UPDATE_FIGHT_POS, UpdateFightPosReq.class,
                (h, req) -> this.updateFightPos(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.SAVE_POSITION, SavePositionReq.class,
                (h, req) -> this.savePosition(req));
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.GET_RANK_LIST, Void.class,
                (h, req) -> this.loadRanks());
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.GET_GOD_LIST, Void.class,
                (h, req) -> this.loadGods());
        useRpcRecv().onRequestResponseTemplate(TeamPvpMsg.GM_RESET_CHALLENGE_TIMESE, String.class,
                (h, req) -> this.gmResetTimes(req));
    }

    private TeamPvpPlayersData getInviteList(TeamPvpInviteListReq req) {
        TeamPvpPlayersData data = new TeamPvpPlayersData();
        List<TeamPvpPlayer> players = parent.getInviteList(req.leaderUid);
        data.players = transPlayerData(players);
        return data;
    }

    private List<TeamPvpPlayerSimpleData> transPlayerData(List<TeamPvpPlayer> players) {
        List<TeamPvpPlayerSimpleData> list = new ArrayList<>();
        for (TeamPvpPlayer player : players) {
            list.add(new TeamPvpPlayerSimpleData(
                    player.ps.snapshot.base,
                    player.score,
                    player.power,
                    player.fightTimes,
                    player.challengeTimes));
        }
        return list;
    }

    private TeamPvpTeamData transTeamData(TeamPvpTeam team) {
        if (team == null) {
            return null;
        }
        List<TeamPvpPlayer> players = parent.findPlayers(team.memberUids);
        return new TeamPvpTeamData(team.uid, transPlayerData(players), team.leaderUid);
    }

    private GameResult<Void> handleInviteApply(TeamPvpInviteApplyReq req) {
        return parent.invite(req.leaderUid, req.inviteUid);
    }
    
    private GameResult<TeamPvpTeamData> handleInviteAnswer(TeamPvpInviteAnswerReq req) {
        GameResult<TeamPvpTeamData> r = new GameResult<>();
        GameResult<TeamPvpTeam> answerRes = parent.answerInvite(req.ok, req.inviteUid, req.leaderUid);
        if (!answerRes.ok()) {
            return r.fail(answerRes);
        }
        r.data = transTeamData(answerRes.data);
        if (req.ok && r.data != null) {
            sendTeamToOther(r.data, r.data.leaderUid);
        }
        return r;
    }

    private void sendTeamToOther(TeamPvpTeamData team, String otherUid) {
        TeamPvpPlayerSimpleData leader = team.members.stream().filter(e -> StringUtils.equals(otherUid, e.base.uid)).findAny().orElse(null);
        if (leader != null) {
            parent.getMsg().sendTeam(leader.base.srvId, leader.base.uid);
        }
    }

    private TeamPvpInviteApplyData getInviteApplyList(String inviteUid) {
        TeamPvpInviteApplyData data = new TeamPvpInviteApplyData();
        data.applyList = transPlayerData(parent.getInviteApplys(inviteUid));
        return data;
    }

    private GameResult<TeamPvpTeamData> changeLeader(ChangeLeaderReq req) {
        GameResult<TeamPvpTeamData> r = new GameResult<>();
        GameResult<TeamPvpTeam> res = parent.changeLeader(req.leaderUid, req.newLeaderUid);
        if (!res.ok()) {
            return r.fail(res);
        }
        r.data = transTeamData(res.data);
        sendTeamToOther(r.data, req.newLeaderUid);
        return r;
    }
    
    private GameResult<TeamPvpTeamData> exitTeam(ExitTeamReq req) {
        GameResult<TeamPvpTeamData> r = new GameResult<>();
        GameResult<TeamPvpTeam> res = parent.exitTeam(req.playerUid);
        if (!res.ok()) {
            return r.fail(res);
        }
        TeamPvpTeam fake = new TeamPvpTeam();
        fake.memberUids = Collections.singletonList(req.playerUid);
        r.data = transTeamData(fake);
        TeamPvpTeam origin = res.data;
        if (origin != null) {
            String otherUid = origin.memberUids.stream().filter(e -> !StringUtils.equals(req.playerUid, e)).findAny().orElse(null);
            if (StringUtils.isNotBlank(otherUid)) {
                List<TeamPvpPlayer> players = parent.findPlayers(Collections.singletonList(otherUid));
                if (CollectionUtils.isNotEmpty(players)) {
                    parent.getMsg().sendTeam(players.get(0).ps.snapshot.base.srvId, otherUid);
                }
            }
        }
        return r;
    }
    
    private SynTeamPvpTeamData syncTeamData(SyncTeamDataReq req) {
        SynTeamPvpTeamData data = new SynTeamPvpTeamData();
        TeamPvpTeam team = parent.syncTeamData(req.ps, req.abbr);
        data.hasRedPoint = parent.hasInvitedList(req.ps.snapshot.uid);
        data.team = transTeamData(team);
        return data;
    }
    
    private GameResult<TeamPvpMatchData> beginToMatch(String playerUid) {
        return parent.matchOpponent(playerUid);
    }

    public GameResult<TeamPvpMatchData> matchRefresh(String playerUid) {
        return parent.matchRefresh(playerUid);
    }

    private GameResult<Void> beginToChallenge(String playerUid) {
        return parent.beginToFight(playerUid);
    }

    private TeamPvpMatchData aheadToPosition(String playerUid) {
        return parent.aheadToPosition(playerUid);
    }

    private TeamPvpPlayerSimpleData searchPlayer(String name) {
        TeamPvpPlayerSimpleData data = null;
        TeamPvpPlayer player = parent.searchPlayer(name);
        if (player != null) {
            data = new TeamPvpPlayerSimpleData(
                    player.ps.snapshot.base,
                    player.score,
                    player.power,
                    player.fightTimes,
                    player.challengeTimes);
        }
        return data;
    }

    private GameResult<TeamPvpMatchData> updateFightPos(UpdateFightPosReq req) {
        return parent.updateFightPosition(req.playerUid, req.newUids);
    }

    private TeamPvpMatchData savePosition(SavePositionReq req) {
        return parent.savePosition(req.ps, req.abbr);
    }

    private List<Rank> loadRanks() {
        return parent.loadRanks();
    }

    private List<Rank> loadGods() {
        return parent.loadGods();
    }

    private GameResult<Void> gmResetTimes(String playerUid) {
        return parent.gmResetTimes(playerUid);
    }
}
